#pragma once

#include<assert.h>

#include<iostream>

#include"Iterator.hpp"
namespace Cherry{

//单个节点
  template<class T>
  struct list_node{
    list_node(const T&val = T())
    :_data(val)
    {
      _prev = _next = nullptr;
    }


    list_node<T>* _prev;//由于自身为类模板，所以需要用类型名用来当作类型
    list_node<T>* _next;
    T _data;
  };

//迭代器 - 用来封装单个节点的指针
  template<class T,class Ref,class Ptr>
    struct __list_iterator{
      typedef list_node<T> node;//
      typedef __list_iterator<T,Ref,Ptr> self;

      __list_iterator(node*n)
       : _node(n)
      {}

      Ptr operator->(){
        return &_node->_data;

      }

      Ref operator*(){
        return _node->_data;
      }

      self& operator++(){
        _node = _node->_next;
        return *this; 
      }

      self operator++(int){
        node*ret = *this;
        _node = _node->_next;
        return ret; 
      }

      self& operator--(){
        _node = _node->_prev;
        return *this; 
      }

      self operator--( int){
        node*ret = *this;
        _node = _node->_prev;
        return ret; 
      }

      bool operator!=(const self&it){
        return it._node!=_node;
      }

      bool operator==(const self&it){
        return it._node==_node;
      }

      node* _node;
    };



//整体框架
  template<class T>
    class list{

    typedef list_node<T> node; //在该类型中list_node<T>重命名为node
    public:  

    typedef __list_iterator<T,T&,T*> iterator;
    typedef __list_iterator<T,const T&,const T*> const_iterator;

    typedef Reverse_iterator<T,T&,T*> reverse_iterator;
    typedef Reverse_iterator<T,const T&,const T*> const_reverse_iterator;

    void empty_init()
    {
      _head = new node;
      _head->_next = _head->_prev = _head;
    }

    template<class Iterator>
      list(Iterator first,Iterator last){
        while(first!=last){
          push_back(*first);
          ++first;
        }
      }

    list(const list<T>& lt){
      empty_init();
      list<T> tmp(lt.begin(),lt.end());
      swap(tmp);
    }

      list(){
        empty_init();
      }

      ~list(){
        clear();
        delete _head;
        _head = nullptr;
      }

      iterator insert(iterator position, const T&val){
       node*newnode = new node(val); 
       node*cur = position._node;

       node*prev = cur->_prev;

       prev->_next = newnode;
       newnode->_prev = prev;

       newnode->_next = cur;
       cur->_prev = newnode;

       return --position;
      }

      void push_back(const T&val ){
      /* node*newnode = new node(val);
        node*prev = _head->_prev;

        prev->_next = newnode;
        newnode->_prev = prev;

        _head->_prev = newnode;
        newnode->_next = _head;*/

      insert(end(),val);
        
      }

      void push_front(const T&val ){
        insert(begin(),val);
      }


      void pop_front(){
        erase(begin());
      }

      void pop_back(){
        erase(--end());
      }

      iterator erase(iterator position){
        assert(position!=end());
        node* prev = position._node->_prev;
        node* next = position._node->_next;
        
        prev->_next = next;
        next->_prev = prev;

        delete position._node;
        
        return iterator(next);
      }

      iterator begin(){
        return iterator(_head->_next);
      }

      iterator end(){
        return iterator(_head);
      }

      const_iterator begin()const{
        return iterator(_head->_next);
      }

      const_iterator end()const{
        return iterator(_head);
      }
        
      void swap(list<T>& tmp){
        std::swap(tmp._head,_head);
      }

      reverse_iterator rbegin(){
        return iterator(_head->_next);
      }

      reverse_iterator rend(){
        return iterator(_head);
      }

      const_reverse_iterator rbegin()const{
        return iterator(_head->_next);
      }

      const_reverse_iterator rend()const{
        return iterator(_head);
      }
      void clear(){
        iterator it = begin();
        while(it!=end()){
          erase(it);
        }
      }

    private:
      node* _head;
    };

}
